//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __CCALLBACKCONTEXT_H__
#define __CCALLBACKCONTEXT_H__

#include <linknode.h>
#include <elastos.h>
#include <critsec.h>
#include <clsdef.h>
#include <elacfg.h>

_ELASTOS_NAMESPACE_USING

EXTERN void _Impl_CallbackSink_FreeCallbackEvent(PCallbackEvent pCallbackEvent);

class CCallbackContext : public IInterface
{
public:
    CARAPI_(PInterface) Probe(REIID riid);
    CARAPI_(UInt32) AddRef();
    CARAPI_(UInt32) Release();
    CARAPI Aggregate(AggregateType type, PInterface pObj);
    CARAPI GetDomain(PInterface *ppObj);

public:
    CCallbackContext()
    {
        m_bExitRequested = FALSE;
        m_bRequestToQuit = FALSE;

        m_eventQueue.Initialize();
        m_currentEvents.Initialize();
        m_pThreadEvent = NULL;
        m_Status = AppletStatus_Created;
        m_nEventsCount = 0;
    }

    ECode Initialize()
    {
        ECode ec = _CEvent_New(FALSE, UNSIGNALED, &m_pThreadEvent);
        if (FAILED(ec)) return ec;
        ec = _CCriticalSection_Initialize(&m_workingLock);
        if (SUCCEEDED(ec)) ec = _CCriticalSection_Initialize(&m_queueLock);
        return ec;
    }

    virtual ~CCallbackContext()
    {
        CancelAllCallbackEvents();

		_CCriticalSection_Terminate(&m_workingLock);
        _CCriticalSection_Terminate(&m_queueLock);

        if (m_pThreadEvent) m_pThreadEvent->Release();
    }

    ECode PostCallbackEvent(
            PCallbackEvent pCallbackEvent);
            
    ECode SendCallbackEvent(
            PCallbackEvent pCallbackEvent,
            Millisecond32 timeOut);
    
    ECode RequestToFinish(AppletFinish flag);

    ECode CancelAllPendingCallbacks(
        PInterface pSender);

    ECode CancelPendingCallback(
        PInterface pSender,
        CallbackEventId id);

    ECode CancelCallbackEvents(
        PInterface pSender,
        CallbackEventId id,
        PVoid pHandlerThis,
        PVoid pHandlerFunc);

    QuitCode HandleCallbackEvents(
        Millisecond32 msTimeOut = INFINITE,
        WaitResult *pResult = NULL,
        Boolean * pbOccured = NULL,
        Flags32 fPriority = 0);

    void CancelAllCallbackEvents();

private:

    DLinkNode* PopEvent();

    void PushEvent(DLinkNode* pEvent);

    Boolean IsExistEvent(PCallbackEvent pEvent);

    Boolean IsExistEvent(
        PInterface pSender,
        CallbackEventId id,
        PVoid pHandlerThis,
        PVoid pHandlerFunc);

    PCallbackEvent GetEvent(Flags32 fPriority);

public:
    CRITICAL_SECTION            m_workingLock;
    CRITICAL_SECTION            m_queueLock;
    Boolean                     m_bExitRequested;
    Boolean                     m_bRequestToQuit;
    DLinkNode                   m_eventQueue;
    DLinkNode                   m_currentEvents;
    IEvent                      *m_pThreadEvent;
    AppletStatus                m_Status;
    Int32                       m_nEventsCount;

private:
    Interlocked                 m_cRef;
};

#endif // __CCALLBACKCONTEXT_H__
